package com.xxl.job.executor.mvc.controller;

import static cn.hutool.core.text.StrPool.BRACKET_END;
import static cn.hutool.core.text.StrPool.BRACKET_START;
import static cn.hutool.core.text.StrPool.DELIM_END;
import static cn.hutool.core.text.StrPool.DELIM_START;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelUtil;
import com.godtree.exception.RankAliasRepeatException;
import com.godtree.service.IRankCrawlerCollectionService;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author Lisicheng
 * @date 20230416
 */
@RestController
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/mongo")
public class MongoController {

  private final MongoTemplate mongoTemplate;

  private final IRankCrawlerCollectionService rankCrawlerCollectionService;

  @PostMapping("/insertMongo")
  public Map<String, Object> insertMongo(@RequestBody List<Map<String, Object>> list) {

    if (CollUtil.isEmpty(list)) {
      return ImmutableMap.of("code", 200, "msg", "空数据");
    }

    String rankId = "rank_id";
    if (list.stream().map(map -> map.get(rankId)).anyMatch(Objects::isNull)) {
      return ImmutableMap.of("code", 500, "msg", "rank_id is null");
    }

    try {
      mongoTemplate.insert(list, "rank");
    } catch (Exception e) {
      log.error("插入mongo失败", e);
      return ImmutableMap.of("code", 500, "msg", ExceptionUtil.stacktraceToString(e));
    }

    try {
      rankCrawlerCollectionService.rankDataByMongo(Convert.toStr(list.get(0).get(rankId)));
    } catch (Exception e) {
      if (e instanceof RankAliasRepeatException) {
        return ImmutableMap.of("code", 500, "msg", e.getMessage());
      }
      log.error("导入数据失败", e);
      return ImmutableMap.of("code", 500, "msg", ExceptionUtil.stacktraceToString(e));
    }

    return ImmutableMap.of("code", 200, "msg", "success");
  }

  /**
   * 插入json格式数据
   *
   * @param json json格式
   * @return 插入结果
   */
  @PostMapping("/insertMongoByJson")
  public Map<String, Object> insertMongoByJson(@RequestParam String json) {

    if (StrUtil.isBlank(json)) {
      return ImmutableMap.of("code", 200, "msg", "空数据");
    }

    if (!json.startsWith(DELIM_START) || !json.endsWith(DELIM_END)) {
      return ImmutableMap.of("code", 500, "msg", "json格式错误");
    }

    String rankId = "rank_id";
    if (JSONUtil.parseObj(json).get(rankId) == null) {
      return ImmutableMap.of("code", 500, "msg", "rank_id is null");
    }

    try {
      mongoTemplate.insert(json, "rank");
    } catch (Exception e) {
      log.error("插入mongo失败", e);
      return ImmutableMap.of("code", 500, "msg", ExceptionUtil.stacktraceToString(e));
    }

    return ImmutableMap.of("code", 200, "msg", "success");
  }

  /**
   * 插入jsonArray格式数据
   *
   * @param jsonArray json数组格式
   * @return 插入结果
   */
  @PostMapping("/insertMongoByJsonArray")
  public Map<String, Object> insertMongoByJsonArray(@RequestParam String jsonArray) {

    if (StrUtil.isBlank(jsonArray)) {
      return ImmutableMap.of("code", 200, "msg", "空数据");
    }

    if (!jsonArray.startsWith(BRACKET_START) || !jsonArray.endsWith(BRACKET_END)) {
      return ImmutableMap.of("code", 500, "msg", "jsonArray格式错误");
    }

    JSONArray data = JSONUtil.parseArray(jsonArray);

    String rankId = "rank_id";
    if (data.stream().map(JSONUtil::parseObj).map(map -> map.get(rankId))
        .anyMatch(Objects::isNull)) {
      return ImmutableMap.of("code", 500, "msg", "rank_id is null");
    }

    try {
      mongoTemplate.insert(data, "rank");
    } catch (Exception e) {
      log.error("插入mongo失败", e);
      return ImmutableMap.of("code", 500, "msg", ExceptionUtil.stacktraceToString(e));
    }

    return ImmutableMap.of("code", 200, "msg", "success");
  }

  /**
   * 上传json文件，插入mongo
   *
   * @param file json文件
   * @return 插入结果
   */
  @PostMapping("/insertMongoByJsonFile")
  public Map<String, Object> insertMongoByJsonFile(@RequestParam("file") MultipartFile file) {

    // 读取MultipartFile，转换为String
    String json;
    try {
      json = new String(file.getBytes());
    } catch (IOException e) {
      log.error("读取文件失败", e);
      return ImmutableMap.of("code", 500, "msg", ExceptionUtil.stacktraceToString(e));
    }

    if (StrUtil.isBlank(json)) {
      return ImmutableMap.of("code", 200, "msg", "空数据");
    }

    // 判断是否为json格式
    boolean notJson = !(json.startsWith(DELIM_START) && json.endsWith(DELIM_END));
    // 判断是否为jsonArray格式
    boolean notJsonArray = !(json.startsWith(BRACKET_START) && json.endsWith(BRACKET_END));
    // 如果不是json格式，也不是jsonArray格式，返回错误信息
    if (notJson && notJsonArray) {
      return ImmutableMap.of("code", 500, "msg", "json格式错误");
    }

    // 如果不是jsonArray格式，转换为jsonArray格式
    if (notJsonArray) {
      json = StrUtil.format("[{}]", json);
    }

    JSONArray jsonArray = JSONUtil.parseArray(json);

    String rankId = "rank_id";
    if (jsonArray.stream().map(JSONUtil::parseObj).map(map -> map.get(rankId))
        .anyMatch(Objects::isNull)) {
      return ImmutableMap.of("code", 500, "msg", "rank_id is null");
    }

    try {
      mongoTemplate.insert(jsonArray, "rank");
    } catch (Exception e) {
      log.error("插入mongo失败", e);
      return ImmutableMap.of("code", 500, "msg", ExceptionUtil.stacktraceToString(e));
    }

    return ImmutableMap.of("code", 200, "msg", "success");
  }

  @PostMapping("/insertMongoByExcel")
  public Map<String, Object> insertMongoByExcel(@RequestParam("file") MultipartFile file) {

    // 读取MultipartFile
    List<Map<String, Object>> list;
    try (InputStream inputStream = file.getInputStream()) {
      list = ExcelUtil.getReader(inputStream).readAll();
    } catch (Exception e) {
      log.error("读取文件失败", e);
      return ImmutableMap.of("code", 500, "msg", ExceptionUtil.stacktraceToString(e));
    }

    if (CollUtil.isEmpty(list)) {
      return ImmutableMap.of("code", 200, "msg", "空数据");
    }

    String rankId = "rank_id";
    if (list.stream().map(map -> map.get(rankId)).anyMatch(Objects::isNull)) {
      return ImmutableMap.of("code", 500, "msg", "rank_id is null");
    }

    try {
      mongoTemplate.insert(list, "rank");
    } catch (Exception e) {
      log.error("插入mongo失败", e);
      return ImmutableMap.of("code", 500, "msg", ExceptionUtil.stacktraceToString(e));
    }

    return ImmutableMap.of("code", 200, "msg", "success");
  }

  /**
   * 清洗数据
   *
   * @param rankId rankId
   * @return 清洗结果
   */
  @PostMapping("/rankDataByMongo")
  public Map<String, Object> rankDataByMongo(@RequestParam String rankId) {

    if (StrUtil.isBlank(rankId)) {
      return ImmutableMap.of("code", 500, "msg", "rank_id is null");
    }

    try {
      rankCrawlerCollectionService.rankDataByMongo(rankId);
    } catch (Exception e) {
      log.error("清洗数据失败", e);
      return ImmutableMap.of("code", 500, "msg", ExceptionUtil.stacktraceToString(e));
    }

    return ImmutableMap.of("code", 200, "msg", "success");
  }

}
